package com.promis.crypto.symmetric;

import com.promis.crypto.BASE64Coder;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

public class PBECodeCipher extends BASE64Coder {

	private static final String ALGORITHM = "PBEWITHMD5andDES";
	
	private static final int ITERATION_COUNT = 100;	//迭代次数
	
	private static PBECodeCipher keyCipher;
	
	public synchronized static PBECodeCipher getInstance() {
		if (keyCipher == null) {
			keyCipher = new PBECodeCipher();
		}
		return keyCipher;
	}
	
	public byte[] initSalt(){  
        SecureRandom random = new SecureRandom();  
        return random.generateSeed(8);  
    }
	
	public SecretKey toKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException{  
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());  
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);  
        return keyFactory.generateSecret(keySpec);  
    }
	
	public byte[] encrypt(byte[] data, SecretKey secretKey, byte[] salt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ 
        return cipher(Cipher.ENCRYPT_MODE, data, secretKey, salt);
    }
	
	public byte[] decrypt(byte[] data, SecretKey secretKey, byte[] salt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{  
        return cipher(Cipher.DECRYPT_MODE, data, secretKey, salt);
    }
	
	private byte[] cipher(int cipherMode, byte[] data, SecretKey secretKey, byte[] salt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ 
		PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATION_COUNT);  
        Cipher cipher = Cipher.getInstance(ALGORITHM);  
        cipher.init(cipherMode, secretKey,parameterSpec);  
        return cipher.doFinal(data);
	}
}
